home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / elm / elm2.4 / lib / parsarpdat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-11  |  6.6 KB  |  248 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: parsarpdat.c,v 5.2 1993/04/12 02:16:32 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 5.2 $   $State: Exp $
  6.  *
  7.  *             Copyright (c) 1993 USENET Community Trust
  8.  *******************************************************************************
  9.  * Bug reports, patches, comments, suggestions should be sent to:
  10.  *
  11.  *    Syd Weinstein, Elm Coordinator
  12.  *    elm@DSI.COM            dsinc!elm
  13.  *
  14.  *******************************************************************************
  15.  * $Log: parsarpdat.c,v $
  16.  * Revision 5.2  1993/04/12  02:16:32  syd
  17.  * Fix year handling bug in date(1) time formats.
  18.  * From: chip@chinacat.unicom.com (Chip Rosenthal)
  19.  *
  20.  * Revision 5.1  1993/01/19  04:46:21  syd
  21.  * Initial Checkin
  22.  *
  23.  *
  24.  ******************************************************************************/
  25.  
  26.  
  27. #include "headers.h"
  28. #include <ctype.h>
  29.  
  30.  
  31. /*
  32.  
  33. Quoting from RFC 822:
  34.      5.  DATE AND TIME SPECIFICATION
  35.  
  36.      5.1.  SYNTAX
  37.  
  38.      date-time   =  [ day "," ] date time        ; dd mm yy
  39.                          ;  hh:mm:ss zzz
  40.  
  41.      day         =  "Mon"  / "Tue" /  "Wed"  / "Thu"
  42.          /  "Fri"  / "Sat" /  "Sun"
  43.  
  44.      date        =  1*2DIGIT month 2DIGIT        ; day month year
  45.                          ;  e.g. 20 Jun 82
  46.  
  47.      month       =  "Jan"  /  "Feb" /  "Mar"  /  "Apr"
  48.          /  "May"  /  "Jun" /  "Jul"  /  "Aug"
  49.          /  "Sep"  /  "Oct" /  "Nov"  /  "Dec"
  50.  
  51.      time        =  hour zone                    ; ANSI and Military
  52.  
  53.      hour        =  2DIGIT ":" 2DIGIT [":" 2DIGIT]
  54.                          ; 00:00:00 - 23:59:59
  55.  
  56.      zone        =  "UT"  / "GMT"                ; Universal Time
  57.                          ; North American : UT
  58.          /  "EST" / "EDT"                ;  Eastern:  - 5/ - 4
  59.          /  "CST" / "CDT"                ;  Central:  - 6/ - 5
  60.          /  "MST" / "MDT"                ;  Mountain: - 7/ - 6
  61.          /  "PST" / "PDT"                ;  Pacific:  - 8/ - 7
  62.          /  1ALPHA                       ; Military: Z = UT;
  63.                          ;  A:-1; (J not used)
  64.                          ;  M:-12; N:+1; Y:+12
  65.          / ( ("+" / "-") 4DIGIT )        ; Local differential
  66.                          ;  hours+min. (HHMM)
  67. */
  68.  
  69.  
  70. int parse_arpa_date(str, entry)
  71. char *str;
  72. struct header_rec *entry;
  73. {
  74.     /*
  75.      * Parse a date field in either RFC-822 or Unix date(1) format.
  76.      * We will fill in the "time_zone", "tz_offset", and "time_sent"
  77.      * parts of the "entry" structure.  Return TRUE on success, FALSE
  78.      * on failure.
  79.      */
  80.  
  81.     char field[STRING], save_tz[STRING];
  82.     int month, day, year, hours, mins, secs, tz, len, i;
  83.  
  84.     /*
  85.      * Since this is an RFC-822 field, there might be parenthetical
  86.      * comments.  Yank them out.  Note that strip_parens() returns
  87.      * a pointer to static data.
  88.      */
  89.     str = strip_parens(str);
  90.  
  91.     /*
  92.      * The first field is an optional day of the week.  If it exists
  93.      * it is supposed to have a trailing comma by RFC-822, but we won't
  94.      * complain if it doesn't.  If the date string was generated by
  95.      * the Unix date(1) command then it won't have the comma.  We don't
  96.      * do anything with this information, just skip over it if it exists.
  97.      */
  98.     if ((len = get_word(str, 0, field, sizeof(field))) < 0)
  99.     goto failed;
  100.     if (cvt_dayname_to_daynum(field, &i))
  101.     str += len;
  102.  
  103.     /*
  104.      * Peek at the next character to determine what format to
  105.      * parse the rest of the line as.
  106.      */
  107.     while (isspace(*str))
  108.     ++str;
  109.     if (!isdigit(*str)) {
  110.  
  111.     /*
  112.      * Parse the line in Unix date(1) format.  The syntax is:
  113.      *
  114.      *    month day hh:mm:ss [tz] year
  115.      *
  116.      * e.g. "Jun 21 06:45:44 CDT 1989".  The timezone is optional.
  117.      */
  118.  
  119.     dprint(7, (debugfile,
  120.         "parse_arpa_date parsing \"%s\" in time(1) format\n", str));
  121.  
  122.     /* <month> */
  123.     if ((len = get_word(str, 0, field, sizeof(field))) < 0 ||
  124.         !cvt_monthname_to_monthnum(field, &month))
  125.         goto failed;
  126.     str += len;
  127.  
  128.     /* <day> */
  129.     if ((len = get_word(str, 0, field, sizeof(field))) < 0 ||
  130.         (day = atonum(field)) < 0)
  131.         goto failed;
  132.     str += len;
  133.  
  134.     /* <hh:mm:ss> */
  135.     if ((len = get_word(str, 0, field, sizeof(field))) < 0 ||
  136.         !cvt_timestr_to_hhmmss(field, &hours, &mins, &secs))
  137.         goto failed;
  138.     str += len;
  139.  
  140.     /* optional <tz> */
  141.     save_tz[0] = save_tz[1] = '\0';
  142.     tz = 0;
  143.     while ((len = get_word(str, 0, field, sizeof(field))) > 0 &&
  144.         cvt_timezone_to_offset(field, &i)) {
  145.         (void) strcat(save_tz, " ");
  146.         (void) strcat(save_tz, field);
  147.         tz += i;
  148.         str += len;
  149.     }
  150.  
  151.     /* <year> */
  152.     if ((len = get_word(str, 0, field, sizeof(field))) < 0 ||
  153.         (year = atonum(field)) < 0)
  154.         goto failed;
  155.     str += len;
  156.  
  157.     /* there might be more...but we ignore it */
  158.  
  159.     } else {
  160.  
  161.     /*
  162.      * Parse the line in RFC-822 format.  The syntax is:
  163.      *
  164.      *    day month year hh:mm:ss zone
  165.      *
  166.      * e.g. "17 Nov 92 23:34:25 CST".
  167.      */
  168.  
  169.     dprint(7, (debugfile,
  170.         "parse_arpa_date parsing \"%s\" in RFC-822 format\n", str));
  171.  
  172.     /* <day> */
  173.     if ((len = get_word(str, 0, field, sizeof(field))) < 0 ||
  174.         (day = atonum(field)) < 0)
  175.         goto failed;
  176.     str += len;
  177.  
  178.     /* <month> */
  179.     if ((len = get_word(str, 0, field, sizeof(field))) < 0 ||
  180.         !cvt_monthname_to_monthnum(field, &month))
  181.         goto failed;
  182.     str += len;
  183.  
  184.     /* <year> */
  185.     if ((len = get_word(str, 0, field, sizeof(field))) < 0 ||
  186.         !cvt_yearstr_to_yearnum(field, &year))
  187.         goto failed;
  188.     str += len;
  189.  
  190.     /* <hh:mm:ss> */
  191.     if ((len = get_word(str, 0, field, sizeof(field))) < 0 ||
  192.         !cvt_timestr_to_hhmmss(field, &hours, &mins, &secs))
  193.         goto failed;
  194.     str += len;
  195.  
  196.     /* <tz> - silently ignore bogus or missing timezones */
  197.     save_tz[0] = save_tz[1] = '\0';
  198.     tz = 0;
  199.     while ((len = get_word(str, 0, field, sizeof(field))) > 0 &&
  200.         cvt_timezone_to_offset(field, &i)) {
  201.         (void) strcat(save_tz, " ");
  202.         (void) strcat(save_tz, field);
  203.         tz += i;
  204.         str += len;
  205.     }
  206.  
  207.     /* there might be more...but we ignore it */
  208.  
  209.     }
  210.  
  211.     strfcpy(entry->time_zone, save_tz+1, sizeof(entry->time_zone));
  212.     entry->tz_offset = tz*60;
  213.     entry->time_sent = make_gmttime(year, month, day, hours, mins-tz, secs);
  214.  
  215.     dprint(7, (debugfile, "  year=%d month=%d day=%d\n", year, month, day));
  216.     dprint(7, (debugfile, "  hours=%d mins=%d secs=%d tz=%d\n",
  217.     hours, mins, secs, tz));
  218.     dprint(7, (debugfile, "  return success\n"));
  219.     return TRUE;
  220.  
  221. failed:
  222.     dprint(4, (debugfile, "parse_arpa_date failed at \"%s\"\n",
  223.     (len <= 0 ? "<premature eol>" : field)));
  224.     return FALSE;
  225. }
  226.  
  227. #ifdef _TEST
  228. int debug = 9999;
  229. FILE *debugfile = stderr;
  230. main()
  231. {
  232.     struct header_rec hdr;
  233.     char buf[1024];
  234.     while (gets(buf) != NULL) {
  235.     if (!parse_arpa_date(buf, &hdr))
  236.         fprintf(stderr, "FAIL %s\n", buf);
  237.     else {
  238.         fprintf(stderr, "OK %s\n", buf);
  239.         fprintf(stderr, "time_zone=%s tz_offset=%d time_sent=%ld\n",
  240.         hdr.time_zone, hdr.tz_offset, hdr.time_sent);
  241.     }
  242.     putc('\n', stderr);
  243.     }
  244.     exit(0);
  245. }
  246. #endif
  247.  
  248.